001 /* 002 * Copyright 2003-2005 The Apache Software Foundation 003 * Copyright 2005 Stephen McConnell 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package net.dpml.cli.validation; 018 019 import java.text.NumberFormat; 020 import java.text.ParsePosition; 021 022 import java.util.List; 023 import java.util.ListIterator; 024 025 import net.dpml.cli.resource.ResourceConstants; 026 import net.dpml.cli.resource.ResourceHelper; 027 028 /** 029 * The <code>NumberValidator</code> validates the string argument 030 * values are numbers. If the value is a number, the string value in 031 * the {@link java.util.List} of values is replaced with the 032 * {@link java.lang.Number} instance. 033 * 034 * A maximum and minimum value can also be specified using 035 * the {@link #setMaximum setMaximum}, and the 036 * {@link #setMinimum setMinimum} methods. 037 * 038 * The following example shows how to limit the valid values 039 * for the age attribute to integers less than 100. 040 * 041 * <pre> 042 * ... 043 * ArgumentBuilder builder = new ArgumentBuilder(); 044 * NumberValidator validator = NumberValidator.getIntegerInstance(); 045 * validator.setMaximum(new Integer(100)); 046 * 047 * Argument age = 048 * builder.withName("age"); 049 * .withValidator(validator); 050 * </pre> 051 * 052 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 053 * @version 1.0.0 054 */ 055 public class NumberValidator implements Validator 056 { 057 /** the <code>NumberFormat</code> being used. */ 058 private NumberFormat m_format; 059 060 /** the lower bound for argument values. */ 061 private Number m_minimum = null; 062 063 /** the upper bound for argument values */ 064 private Number m_maximum = null; 065 066 /** 067 * Creates a new NumberValidator based on the specified NumberFormat 068 * @param format the format of numbers to accept 069 */ 070 public NumberValidator( final NumberFormat format ) 071 { 072 setFormat( format ); 073 } 074 075 /** 076 * Returns a <code>NumberValidator</code> for a currency format 077 * for the current default locale. 078 * @return a <code>NumberValidator</code> for a currency format 079 * for the current default locale. 080 */ 081 public static NumberValidator getCurrencyInstance() 082 { 083 return new NumberValidator( NumberFormat.getCurrencyInstance() ); 084 } 085 086 /** 087 * Returns a <code>NumberValidator</code> for an integer number format 088 * for the current default locale. 089 * @return a <code>NumberValidator</code> for an integer number format 090 * for the current default locale. 091 */ 092 public static NumberValidator getIntegerInstance() 093 { 094 final NumberFormat format = NumberFormat.getNumberInstance(); 095 format.setParseIntegerOnly( true ); 096 return new NumberValidator( format ); 097 } 098 099 /** 100 * Returns a <code>NumberValidator</code> for a percentage format 101 * for the current default locale. 102 * @return a <code>NumberValidator</code> for a percentage format 103 * for the current default locale. 104 */ 105 public static NumberValidator getPercentInstance() 106 { 107 return new NumberValidator( NumberFormat.getPercentInstance() ); 108 } 109 110 /** 111 * Returns a <code>NumberValidator</code> for a general-purpose 112 * number format for the current default locale. 113 * @return a <code>NumberValidator</code> for a general-purpose 114 * number format for the current default locale. 115 */ 116 public static NumberValidator getNumberInstance() 117 { 118 return new NumberValidator( NumberFormat.getNumberInstance() ); 119 } 120 121 /** 122 * Validate the list of values against the list of permitted values. 123 * If a value is valid, replace the string in the <code>values</code> 124 * {@link java.util.List} with the {@link java.lang.Number} instance. 125 * 126 * @param values the list of values to validate 127 * @exception InvalidArgumentException if a value is invalid 128 * @see net.dpml.cli.validation.Validator#validate(java.util.List) 129 */ 130 public void validate( final List values ) throws InvalidArgumentException 131 { 132 for( final ListIterator i = values.listIterator(); i.hasNext();) 133 { 134 final Object next = i.next(); 135 if( next instanceof Number ) 136 { 137 return; 138 } 139 final String value = (String) next; 140 final ParsePosition pp = new ParsePosition( 0 ); 141 final Number number = m_format.parse( value, pp ); 142 if( pp.getIndex() < value.length() ) 143 { 144 throw new InvalidArgumentException( value ); 145 } 146 if( 147 ( ( m_minimum != null ) && ( number.doubleValue() < m_minimum.doubleValue() ) ) 148 || ( ( m_maximum != null ) && ( number.doubleValue() > m_maximum.doubleValue() ) ) 149 ) 150 { 151 throw new InvalidArgumentException( 152 ResourceHelper.getResourceHelper().getMessage( 153 ResourceConstants.NUMBERVALIDATOR_NUMBER_OUTOFRANGE, 154 new Object[]{value} ) ); 155 } 156 i.set( number ); 157 } 158 } 159 160 /** 161 * Return the format being used to validate argument values against. 162 * 163 * @return the format being used to validate argument values against. 164 */ 165 public NumberFormat getFormat() 166 { 167 return m_format; 168 } 169 170 /** 171 * Specify the format being used to validate argument values against. 172 * 173 * @param format the format being used to validate argument values against. 174 */ 175 protected void setFormat( NumberFormat format ) 176 { 177 m_format = format; 178 } 179 180 /** 181 * Return the maximum value allowed for an argument value. 182 * 183 * @return the maximum value allowed for an argument value. 184 */ 185 public Number getMaximum() 186 { 187 return m_maximum; 188 } 189 190 /** 191 * Specify the maximum value allowed for an argument value. 192 * 193 * @param maximum the maximum value allowed for an argument value. 194 */ 195 public void setMaximum( Number maximum ) 196 { 197 m_maximum = maximum; 198 } 199 200 /** 201 * Return the minimum value allowed for an argument value. 202 * 203 * @return the minimum value allowed for an argument value. 204 */ 205 public Number getMinimum() 206 { 207 return m_minimum; 208 } 209 210 /** 211 * Specify the minimum value allowed for an argument value. 212 * 213 * @param minimum the minimum value allowed for an argument value. 214 */ 215 public void setMinimum( Number minimum ) 216 { 217 m_minimum = minimum; 218 } 219 }